﻿/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Daidalos.Utilities;

namespace Daidalos.Graphics
{

    /// <summary>
    ///     The render window encapsules the window object of the OS' 
    ///     window manager.
    /// </summary>
    public sealed class RenderWindow : Form
    {

        #region Attributes
        /// <summary>
        ///     A flag indicating the present of a usable stencil
        ///     buffer.
        /// </summary>
        private bool hasStencilBuffer = false;

        /// <summary>
        ///     The width of the window.
        /// </summary>
        private int width = 800;

        /// <summary>
        ///     The height of the window.
        /// </summary>
        private int height = 600;

        /// <summary>
        ///     Syncronize rendering and screen refresh.
        /// </summary>
        private bool vsync = false;
        #endregion

        #region Accessors
        /// <summary>
        ///     Defines the accessor to the VSync-flag.
        /// </summary>
        public bool VSync
        {
            get
            {
                return vsync;
            }
            set
            {
                vsync = value;
            }
        }

        /// <summary>
        ///     Implements a selector for the stencil buffer
        ///     flag.
        /// </summary>
        public bool HasStencilBuffer
        {
            get
            {
                return hasStencilBuffer;
            }
        }

        /// <summary>
        ///     Defines the accessor to the window's width.
        /// </summary>
        new public int Width
        {
            get
            {
                return width;
            }
            set
            {
                width = (value < 0) ? 0 : value;
            }
        }

        /// <summary>
        ///     Read/Write the window's height
        ///     Define the accessor to the window's height.
        /// </summary>
        new public int Height
        {
            get
            {
                return height;
            }
            set
            {
                height = (value < 0) ? 0 : value;
            }
        }
        #endregion

        #region Methods
        /// <summary>
        ///     This method creates a rendering window using the OS' window manager. The supplied
        ///     parameters are used to setup the window behaviour.
        /// </summary>
        /// <param name="width">
        ///     The desired window width.
        /// </param>
        /// <param name="height">
        ///     The desired window height.
        /// </param>
        /// <param name="fullscreen">
        ///     Is fullscreen mode desired?
        /// </param>
        /// <param name="title">
        ///     The desired window title.
        /// </param>
        public void CreateWindow(int width, int height, bool fullscreen, string title)
        {
            // Save dimensions.
            Width   = width;
            Height  = height;

            // Set the window attributes.
            this.ClientSize = new System.Drawing.Size(width, height);
            this.Text       = title;

            // Try to setup DirectX.
            try
            {
                // Setup the present parameters
                PresentParameters presentParams = new PresentParameters();
                presentParams.Windowed          = !fullscreen;

                // If we wanna go fullscreen, we have to tune some things...
                if(fullscreen)
                {
                    // Fill the present structure.
                    LogManager.Instance.Log("Going fullscreen.");
                    if (vsync)
                    {
                        LogManager.Instance.Log("  + Enabling VSync.");
                        presentParams.PresentationInterval = PresentInterval.Default;
                    }
                    else
                    {
                        LogManager.Instance.Log("  + Disabling VSync.");
                        presentParams.PresentationInterval = PresentInterval.Immediate;
                    }
                }

                // Setup the display mode.
                LogManager.Instance.Log("  + Getting current displaymode format.");
                Format current = fullscreen ? Format.X8R8G8B8 : Manager.Adapters[0].CurrentDisplayMode.Format;

                // Setup multisampling.
                presentParams.MultiSample = MultiSampleType.None;
                
                // Setup the back buffer[s].
                LogManager.Instance.Log("  + Setting backbuffer count.");
                presentParams.BackBufferCount = 1;
                LogManager.Instance.Log("  + Setting backbuffer size.");
                presentParams.BackBufferWidth = Width;
                presentParams.BackBufferHeight = Height;

                // Setup backbuffer format & behaviour.
                LogManager.Instance.Log("  + Setting backbuffer format & behaviour.");
                presentParams.BackBufferFormat = current;
                presentParams.SwapEffect = SwapEffect.Discard;

                // Now, create the damn device.
                RenderDevice.Instance.Device = new Device(0, DeviceType.Hardware, this, CreateFlags.HardwareVertexProcessing, presentParams);
                this.Show();
            }
            catch(DirectXException)
            {
                // Something went wrong.
                throw new Exception("Error while initialising render-window!");
            }
        }

        /// <summary>
        ///     The system call to repaint the window is passed to the engine's rendering
        ///     call.
        /// </summary>
        /// <param name="args">
        ///     Some arguments, that do not matter for us.
        /// </param>
        protected override void OnPaint(PaintEventArgs args)
        {
            RenderDevice.Instance.Render();
        }

        // TODO: implement key handler!
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if ((int)(byte)e.KeyChar == (int)System.Windows.Forms.Keys.Escape)
                this.Close();
            if ((int)(byte)e.KeyChar == (int)System.Windows.Forms.Keys.Enter)
                RenderDevice.Instance.loading = false;
        }

        protected override void OnResize(System.EventArgs e)
        {
            LogManager.Instance.Log("Resizing window to " + this.Size.Width + "x" + this.Size.Height);
            Width = this.Size.Width;
            Height = this.Size.Height;
			Utilities.ResourceManager.Instance.ReloadTextures();
			base.OnResize(e);
		}
        #endregion
    }

}
